package com.zhiyizhen.handheld.common;

import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.exifinterface.media.ExifInterface;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;

/**
 * description 图片处理工具类
 */
public class ImageUtil {
    private ImageUtil() {
    }

    private static final int COMPRESS_MAX_LENGTH_DEFAULT = 1080;// 图片最大边长
    private static final long COMPRESS_MAX_SIZE_DEFAULT = 500 * 1024L;// 图片最大大小

    private static final String FILE = "file";
    private static final String CONTENT = "content";

    private static final int WATERMARK_PADDING = 30;
    private static final Paint WATERMARK_PAINT = new Paint(Paint.ANTI_ALIAS_FLAG);

    static {
        WATERMARK_PAINT.setColor(Color.WHITE);
        WATERMARK_PAINT.setTextSize(26);
        WATERMARK_PAINT.setShadowLayer(5, 3, 3, Color.BLACK);
    }

    /**
     * 压缩图片
     *
     * @param imgUri        图片原始地址
     * @param outFile       保存的文件对象
     * @param showWatermark 是否添加水印
     */
    public static File compressImage(@NonNull Uri imgUri, @NonNull File outFile, boolean showWatermark) throws IOException {
        return compressImage(imgUri, outFile, COMPRESS_MAX_LENGTH_DEFAULT, COMPRESS_MAX_SIZE_DEFAULT, showWatermark);
    }

    /**
     * 压缩图片
     *
     * @param imgUri        图片原始地址
     * @param outFile       保存的文件对象
     * @param maxLen        图片最大变长（分辨率）
     * @param limitSize     图片文件大小
     * @param showWatermark 是否添加水印
     */
    public static File compressImage(@NonNull Uri imgUri, @NonNull File outFile, int maxLen, long limitSize, boolean showWatermark) throws IOException {
        File parentFile = outFile.getParentFile();
        if (parentFile != null && !parentFile.exists()) {
            //noinspection ResultOfMethodCallIgnored
            parentFile.mkdirs();
        }

        try (FileOutputStream fileOutputStream = new FileOutputStream(outFile)) {
            // write the compressed bitmap at the destination specified by outFile.
            Bitmap scaledBitmap = createScaledBitmapFromUri(imgUri, maxLen);
            if (showWatermark) {
                Bitmap bitmap = drawWatermark(scaledBitmap);
                scaledBitmap.recycle();
                scaledBitmap = bitmap;
            }

            int quality = calculateQuality(scaledBitmap, limitSize);
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream);
            scaledBitmap.recycle();
        }

        return outFile;
    }

    /**
     * 压缩图片
     */
    public static File compressImage(@NonNull Bitmap bitmap, @NonNull File outFile, boolean showWatermark) throws IOException {
        return compressImage(bitmap, outFile, COMPRESS_MAX_SIZE_DEFAULT, showWatermark);
    }

    /**
     * 压缩图片
     */
    public static File compressImage(@NonNull Bitmap bitmap, @NonNull File outFile, long limitSize, boolean showWatermark) throws IOException {
        File parentFile = outFile.getParentFile();
        if (parentFile != null && !parentFile.exists()) {
            //noinspection ResultOfMethodCallIgnored
            parentFile.mkdirs();
        }

        try (FileOutputStream fileOutputStream = new FileOutputStream(outFile)) {
            if (showWatermark) {
                bitmap = drawWatermark(bitmap);
            }

            int quality = calculateQuality(bitmap, limitSize);
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, fileOutputStream);
            bitmap.recycle();
        }

        return outFile;
    }

    private static InputStream getStreamFromUri(Uri imgUri) throws IOException {
        final String scheme = imgUri.getScheme();
        if (TextUtils.isEmpty(scheme)) {
            throw new IOException("imgUri scheme is null");
        }

        InputStream stream = null;
        if (FILE.equals(scheme) && imgUri.getPath() != null) {
            stream = new FileInputStream(imgUri.getPath());
        } else if (CONTENT.equals(scheme)) {
            ContentResolver resolver = AppUtil.getContext().getContentResolver();
            stream = resolver.openInputStream(imgUri);
        }

        return stream;
    }

    private static Bitmap createScaledBitmapFromUri(Uri imgUri, int maxLen) throws IOException {
        InputStream stream = getStreamFromUri(imgUri);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(stream, null, options);
        if (stream != null) {
            stream.close();
        }

        final int width = options.outWidth;
        final int height = options.outHeight;
        int reqWidth;
        int reqHeight;
        if (width > height) {
            reqWidth = maxLen;
            reqHeight = (reqWidth * height) / width;
        } else {
            reqHeight = maxLen;
            reqWidth = (reqHeight * width) / height;
        }

        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

        stream = getStreamFromUri(imgUri);
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        Bitmap scaledBitmap = BitmapFactory.decodeStream(stream, null, options);
        if (stream != null) {
            stream.close();
        }
        try {
            stream = getStreamFromUri(imgUri);
            scaledBitmap = rotateBitmap(stream, scaledBitmap);
            if (stream != null) {
                stream.close();
            }
        } catch (IOException e) {
            LogUtil.e(e);
        }
        return scaledBitmap;
    }

    private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int width = options.outWidth;
        final int height = options.outHeight;
        int inSampleSize = 1;


        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    /**
     * 计算压缩到指定大小时，图片的质量
     *
     * @param bitmap    Bitmap对象
     * @param limitSize 指定的最大值
     */
    private static int calculateQuality(Bitmap bitmap, long limitSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int quality = 100;
        do {
            baos.reset();
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, baos);
            int multiple = (int) Math.max(2, Math.min(45, ((baos.size() - limitSize / 2) / limitSize) * 3));
            quality = quality - multiple;
        } while (baos.size() > limitSize || quality <= 5);

        try {
            baos.close();
        } catch (IOException e) {
            LogUtil.e(e);
        }

        return quality;
    }

    public static Bitmap rotateBitmap(InputStream imgStream, Bitmap bitmap) throws IOException {
        ExifInterface ei = new ExifInterface(imgStream);
        int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);

        Bitmap rotatedBitmap;
        switch (orientation) {

            case ExifInterface.ORIENTATION_ROTATE_90:
                rotatedBitmap = rotateBitmap(bitmap, 90);
                break;

            case ExifInterface.ORIENTATION_ROTATE_180:
                rotatedBitmap = rotateBitmap(bitmap, 180);
                break;

            case ExifInterface.ORIENTATION_ROTATE_270:
                rotatedBitmap = rotateBitmap(bitmap, 270);
                break;

            case ExifInterface.ORIENTATION_NORMAL:
            default:
                rotatedBitmap = bitmap;
                break;
        }
        return rotatedBitmap;
    }

    private static Bitmap rotateBitmap(Bitmap source, float angle) {
        Matrix matrix = new Matrix();
        matrix.postRotate(angle);
        return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
                matrix, true);
    }

    /**
     * 加水印
     *
     * @param src 原始Bitmap对象
     */
    private static Bitmap drawWatermark(Bitmap src) {
        Bitmap bitmap = src.copy(src.getConfig(), true);
        Canvas canvas = new Canvas(bitmap);

        List<String> watermarks = new ArrayList<>();
        watermarks.add(DateUtil.getDateFormat(DateUtil.YYYY_MM_DD_HH_MM_SS).format(Calendar.getInstance().getTime()));
        Collections.reverse(watermarks);// 由下往上绘

        int offsetY = 0;
        Rect bounds = new Rect();
        for (String watermark : watermarks) {
            WATERMARK_PAINT.getTextBounds(watermark, 0, watermark.length(), bounds);
            final int drawX = bitmap.getWidth() - bounds.width() - WATERMARK_PADDING;
            final int drawY = bitmap.getHeight() - WATERMARK_PADDING - offsetY;
            canvas.drawText(watermark, drawX, drawY, WATERMARK_PAINT);
            offsetY += bounds.height();
        }

        return bitmap;
    }

}
